package cn.xunjie.ymcc.service.impl;

import cn.xunjie.ymcc.constants.CommonConstants;
import cn.xunjie.ymcc.constants.SmsCodeConstants;
import cn.xunjie.ymcc.constants.YmccError;
import cn.xunjie.ymcc.domain.MessageSms;
import cn.xunjie.ymcc.domain.User;
import cn.xunjie.ymcc.dto.RedisRegisterDto;
import cn.xunjie.ymcc.dto.RegisterDto;
import cn.xunjie.ymcc.exception.GlobalException;
import cn.xunjie.ymcc.feignClients.UserFeignClient;
import cn.xunjie.ymcc.service.IMessageSmsService;
import cn.xunjie.ymcc.service.IVerifyCodeService;
import cn.xunjie.ymcc.util.StrUtils;
import cn.xunjie.ymcc.util.VerifyCodeUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private UserFeignClient userFeignClient;
    @Autowired
    private SmsCodeConstants smsCodeConstants;
    @Autowired
    private IMessageSmsService messageSmsService;


    @Override
    public String imageCode(String key) {
        if (!StringUtils.hasLength(key)) {
            throw new GlobalException("key不能为空！！！");
        }
//        (每次都是直接生成新的，但是要覆盖前面的)
//        。生成code = 9527
        String code = StrUtils.getComplexRandomString(4);
//        。保存redis，设置过期时间  key是什么==前端请求给我传递的UUID
        redisTemplate.opsForValue().set(
                key,//前端传递的UUID
                code, //图片中的码儿
                5,//过期时间
                TimeUnit.MINUTES);//过期时间的单位
//        。使用2D引擎把code画成图
//        。把图使用Base64编码成字符串
//        。返回Base64编码的字符串
        return VerifyCodeUtils.verifyCode(100, 38, code);
    }

    @Override
    public void sendSmsCode(RegisterDto dto) {
        String imageCodeKey = dto.getImageCodeKey();
        String phone = dto.getMobile();
        String imageCodeValue = dto.getImageCode();

//        一：校验
//        1.空校验
        if(StringUtils.isEmpty(phone) || StringUtils.isEmpty(imageCodeKey)
                || StringUtils.isEmpty(imageCodeValue)){
            throw new GlobalException(YmccError.ERROR_XINXI.getMessage(),YmccError.ERROR_XINXI.getCode());
        }
//        2.校验图形验证码，根据imageCodeKey从redis获取图形验证码
        Object imageCodeTmp = redisTemplate.opsForValue().get(imageCodeKey);
//        。获取不到 图形验证码过期，重新获取
        if(imageCodeTmp == null){
            throw new GlobalException(YmccError.ERROR_TUXING.getMessage(),YmccError.ERROR_TUXING.getCode());
        }
//        。获取到了，比对图形验证码是否正确  比对不要区分大小写
        if(!imageCodeTmp.toString().equalsIgnoreCase(imageCodeValue)){
//                - 不正确，提示输入图形验证码错误
            throw new GlobalException(YmccError.ERROR_NOTTUXING.getMessage(),YmccError.ERROR_NOTTUXING.getCode());
        }
//                - 正确，往下走
//        3.校验手机号是否注册过了
        User user = JSONObject.parseObject(JSON.toJSONString(userFeignClient.loadByPhone(phone).getData()), User.class);
        /*Object data = userFeignClient.loadByPhone(phone).getData();*/

//        。注册过了，滚去登录
        if(user != null){
            throw new GlobalException(YmccError.ERROR_YICUNZAI.getMessage(),YmccError.ERROR_YICUNZAI.getCode());
        }
        String key = String.format(CommonConstants.REGISTER_PHONE_PRIFIX, phone);//register:158234234
        //发送验证码逻辑
        sendSmsCode(key,phone);
    }


    private void sendSmsCode(String key,String phone) {
        //        。没有注册过，往下走
//        二：短信验证码逻辑
//        1.根据手机号拼接key，159:register，从redis获取曾今可能发送的短信验证码

        List <MessageSms> list = messageSmsService.loadByPhone(phone);
        /*AssertUtil.isNull(messageSms,"已加入黑名单");*/
        if(list.size() != 0){
           throw new GlobalException("已加入黑名单");
        }

        Date now = new Date();
        Object smsCodeTmp = redisTemplate.opsForValue().get(key);//9527:232468742341657213
//        1.1 获取到了
        String smsCode = "";
        if(smsCodeTmp != null){
//        1.1.1 校验是否过了一分钟重发时间 value
           /* Long oldTime = Long.valueOf(smsCodeTmp.toString().split(":")[1]);*/
            RedisRegisterDto registerDto = (RedisRegisterDto) smsCodeTmp;
            if((now.getTime() - registerDto.getTime()) <= 1*60*1000){
//        。小于一分钟  哥屋恩
                throw new GlobalException(YmccError.ERROR_GAOPOHUAI.getMessage(),YmccError.ERROR_GAOPOHUAI.getCode());
            }
//        。大于一分中 （还没有到3分钟，验证码还有效），
//        使用还没过期的验证码，刷新过期时间
            smsCode = registerDto.getCode();
            /*smsCode = smsCodeTmp.toString().split(":")[0];//9527*/
        }else{
//        1.2 获取不到
//        1.2.1.生成新的短信验证码
            smsCode = StrUtils.getComplexRandomString(4);
        }
//        3.存储redis 设置一个过期时间
        RedisRegisterDto redisRegisterDto = new RedisRegisterDto(smsCode,now.getTime());
        redisTemplate.opsForValue().set(key,redisRegisterDto,smsCodeConstants.getTimeout(),TimeUnit.SECONDS);


        /*String smsCodeValue = smsCode + ":" + System.currentTimeMillis();
        redisTemplate.opsForValue().set(
                key,
                smsCodeValue,
                3,
                TimeUnit.MINUTES
        );*/
//        4.发送短信
        //SmsUtils.sendSms(phone,"亲，您的验证码是："+smsCode+"。请在3分钟内使用！！");
        /*System.out.println("亲，您的验证码是：" + smsCode + "。请在3分钟内使用！！");*/
        String message = String.format(smsCodeConstants.getSmsmessage(), smsCode);
        log.info(message);
        saveMessageSms(now, smsCode, message,phone);
    }
    private void saveMessageSms(Date now, String code,String message,String phone) {
        MessageSms messageSms = new MessageSms();
        messageSms.setContent(message);
        messageSms.setSendTime(now);
        messageSms.setTitle(smsCodeConstants.getTitle());
        // 获取请求体 request
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        messageSms.setIp(request.getRemoteAddr());//获取IP地址
        messageSms.setPhone(phone);
        messageSmsService.insert(messageSms);
    }
}




